package com.decent.manager.config.security.aspect;

import cn.hutool.core.util.StrUtil;
import com.decent.common.constant.Constants;
import com.decent.common.enums.AuthExceptionEnum;
import com.decent.common.exception.AuthException;
import com.decent.manager.system.auth.content.LoginContextHandler;
import com.decent.manager.system.auth.vo.LoginUser;
import com.decent.manager.config.security.annotion.LogicTypeEnum;
import com.decent.manager.config.security.annotion.Permission;
import com.decent.manager.config.security.context.LoginContext;
import com.decent.manager.system.util.CommonServletUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * 权限过滤Aop切面
 *
 * @author 张子旭
 * @date 2022/1/20
 */
@Slf4j
@Aspect
public class PermissionAop {
    /**
     * 权限切入点
     */
    @Pointcut("@annotation(com.decent.manager.config.security.annotion.Permission)")
    private void getPermissionPointCut() {
    }

    /**
     * 执行权限过滤
     */
    @Before("getPermissionPointCut()")
    public void doPermission(JoinPoint joinPoint) {
        LoginContext current = LoginContextHandler.current();
        LoginUser loginUser = current.getLoginUser();
        // 如果是超级管理员，直接放过权限校验
        boolean isSuperAdmin = current.isSuperAdmin();
        if (isSuperAdmin) {
            return;
        }

        // 如果不是超级管理员，则开始进行权限校验
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        Permission permission = method.getAnnotation(Permission.class);

        // 当前方法需要的角色集合
        String[] requireRoles = permission.value();

        // 逻辑类型
        LogicTypeEnum logicTypeEnum = permission.logicType();
        // 首先校验当前用户有没有 当前请求requestUri的权限
        HttpServletRequest request = CommonServletUtil.getRequest();
        // 如果当前接口需要特定的角色权限，则校验参数上的特殊角色当前用户有没
        if (requireRoles.length != 0) {
            String roles = StrUtil.join(Constants.COMMA, requireRoles);
            boolean hasSpecialRolePermission = LogicTypeEnum.AND.equals(logicTypeEnum) ?
                    current.hasAllRole(roles) :
                    current.hasAnyRole(roles);
            if (!hasSpecialRolePermission) {
                log.error("当前账户[{}]无[{}]访问权限", loginUser.getUserAccount(), request.getRequestURI());
                throw new AuthException(AuthExceptionEnum.VALID_CODE_ERROR);
            }
        }
    }
}
